package com.chuangke.config;

import java.util.ArrayList;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.MethodInvokingFactoryBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.ProviderManager;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.config.annotation.web.configurers.HeadersConfigurer;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;

import com.chuangke.common.utils.SpringContextUtil;
import com.chuangke.login.config.LoginConfig;
import com.chuangke.security.authorization.CommonAuthorizationManager;
import com.chuangke.security.filter.JwtAuthenticationFilter;
import com.chuangke.security.handler.CkLogoutSuccessHandler;

/**
 * Spring Security Config
 *
 * @author chuangke
 * @date Nov 20, 2018
 */
@Configuration
@EnableWebSecurity
public class WebSecurityConfig {
	
	@Autowired
	private LoginConfig loginConfig ;

	@Autowired
	private UserDetailsService userDetailsService;

	@Autowired
	private JwtAuthenticationFilter jwtAuthenticationFilter;

	@Autowired
	private CkLogoutSuccessHandler ckLogoutSuccessHandler;

	@Autowired
	private CommonAuthorizationManager commonAuthorizationManager;

	/**
	 * @anyRequest | 匹配所有请求路径
	 * @access | SpringEl表达式结果为true时可以访问
	 * @anonymous | 匿名可以访问
	 * @denyAll | 用户不能访问
	 * @fullyAuthenticated | 用户完全认证可以访问（非remember-me下自动登录）
	 * @hasAnyAuthority | 如果有参数，参数表示权限，则其中任何一个权限可以访问
	 * @hasAnyRole | 如果有参数，参数表示角色，则其中任何一个角色可以访问
	 * @hasAuthority | 如果有参数，参数表示权限，则其权限可以访问
	 * @hasIpAddress | 如果有参数，参数表示IP地址，如果用户IP和参数匹配，则可以访问
	 * @hasRole | 如果有参数，参数表示角色，则其角色可以访问
	 * @permitAll | 用户可以任意访问
	 * @rememberMe | 允许通过remember-me登录的用户访问
	 * @authenticated | 用户登录后可访问
	 */
	@Bean
	public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
		http.cors(Customizer.withDefaults());
		http.csrf(AbstractHttpConfigurer::disable);
		http.authorizeHttpRequests((authorizeHttpRequests) -> authorizeHttpRequests
				// 跨域预检请求
				.antMatchers(HttpMethod.OPTIONS, "/**").permitAll()
				// 白名单，不需要校验
				.requestMatchers(getAntPathRequestMatchers()).permitAll()
				// 其他所有请求需要身份认证
				.anyRequest().access(commonAuthorizationManager));
		http.sessionManagement(
				(sessionManagement) -> sessionManagement.sessionCreationPolicy(SessionCreationPolicy.STATELESS));
		http.headers((headers) -> headers.frameOptions(HeadersConfigurer.FrameOptionsConfig::disable));
		http.logout((logout) -> logout.logoutSuccessHandler(ckLogoutSuccessHandler));

		http.addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class)
				.userDetailsService(userDetailsService);

		return http.build();
	}

	private AntPathRequestMatcher[] getAntPathRequestMatchers() {
		String[] authWhites = getAuthWhiteList();
		AntPathRequestMatcher[] apms = new AntPathRequestMatcher[authWhites.length];
		for (int i = 0; i < authWhites.length; i++) {
			apms[i] = new AntPathRequestMatcher(authWhites[i]);
		}
		System.out.print("");
		return apms;
	}

	private String[] getAuthWhiteList() {
        return new String[]{ // "/", // 首页
				"/webjars/**", // web jars
				"/druid/**", // 查看SQL监控（druid）
				"/file/img", // 缩略图加载
				"/swagger-ui/**", "/swagger-resources/**", "/v2/api-docs", "/v3/api-docs",

				"/file/view/**", "/filesearch/**", "/elastic/**", "/elasticMgr/**", "/jasper/**",
				"/attachment/**", // 附件上传

				"/regulation/elastic/**",
//				"/regulation/**",
				"/law/**",
				"/leave/external",
				"/meeting/**",
				"/sinopec/**",
				
				"/qhse/actionplan/init",//初始行动计划
				
				"/mds/knowledge/**",
				"/zchkcl/processSimulate/updateInfoByPython",//更新仿真状态
				"/zchkcl/processSimulate/transferResultFile",//获取仿真结果

				"/login", // 登录页面
				"/signout", // 退出登录
				"/register", // 注册页面
				"/dept/findlastlevel", // 注册查询机构
				"/captcha.jpg**" // 验证码
		};
	}

//	@Bean
//	public PasswordEncoder getBCryptPasswordEncoder() {
//		return new BCryptPasswordEncoder();
//	}

	@Bean
	public AuthenticationManager authenticationManager() {
		List<AuthenticationProvider> providers = new ArrayList<>() ;
		if(loginConfig.isOpenPassLogin()) {
			providers.add((AuthenticationProvider)SpringContextUtil.getBean("commonAuthenticationProvider")) ;
		}
		return new ProviderManager(providers);
	}

	@Bean
	public MethodInvokingFactoryBean methodInvokingFactoryBean() {
		MethodInvokingFactoryBean methodInvokingFactoryBean = new MethodInvokingFactoryBean();
		methodInvokingFactoryBean.setTargetClass(SecurityContextHolder.class);
		methodInvokingFactoryBean.setTargetMethod("setStrategyName");
		methodInvokingFactoryBean.setArguments(SecurityContextHolder.MODE_INHERITABLETHREADLOCAL);
		return methodInvokingFactoryBean;
	}
}